package leetcode.leetcode_hot100;

import java.util.ArrayList;
import java.util.List;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;

public class T0039 {
    class Solution {
        List<List<Integer>> res;
        int[] candidates;
        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            this.candidates=candidates;
            res=new ArrayList<List<Integer>>();
            dfs(new ArrayList<Integer>(),0,target);
            return res;
        }
        public void dfs(ArrayList<Integer> tmp,int index,int target){
            if(index>candidates.length-1){
                return;
            }
            if(target==0){
                res.add(new ArrayList(tmp));
                return;
            }
            //直接跳过，不选取当前数
            dfs(tmp,index+1,target);
            //选择当前数
            if(target>=candidates[index]){
                tmp.add(candidates[index]);
                dfs(tmp,index,target-candidates[index]);
                //恢复
                tmp.remove(tmp.size()-1);
                return;
            }
        }
    }
    class Solution2 {

        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            int len = candidates.length;
            List<List<Integer>> res = new ArrayList<>();
            if (len == 0) {
                return res;
            }

            // 排序是剪枝的前提
            Arrays.sort(candidates);
            Deque<Integer> path = new ArrayDeque<>();
            dfs(candidates, 0, len, target, path, res);
            return res;
        }

        private void dfs(int[] candidates, int begin, int len, int target, Deque<Integer> path, List<List<Integer>> res) {
            // 由于进入更深层的时候，小于 0 的部分被剪枝，因此递归终止条件值只判断等于 0 的情况
            if (target == 0) {
                res.add(new ArrayList<>(path));
                return;
            }

            for (int i = begin; i < len; i++) {
                // 重点理解这里剪枝，前提是候选数组已经有序，
                if (target - candidates[i] < 0) {
                    break;
                }

                path.addLast(candidates[i]);
                dfs(candidates, i, len, target - candidates[i], path, res);
                path.removeLast();
            }
        }
    }
}

